﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Collections;
using System.Threading;
using System.Security.Cryptography;
using System.IO.Compression;
namespace SpyTxT
{
    /*
     * 数据处理,包括分拆和组合,还有解密处理 .
     * 
     */
    class DoNetData : UIAction,IInitUIAction
    {
        private MemoryStream recvxml = new MemoryStream();
        private ArrayList recvlist = new ArrayList();
        private string cryptkey;
        private int recvexdatalen = 0;
        public bool bLog = false;
 

        public void InitUIAction(IUIAction p)
        {
            this.SetUIAction(p);
        }
        /*
         * 处理数据入口 
         * data 数据数组
         * 
         */
        public void DoXmlData(byte[] data)
        {

            try
            {
                Monitor.Enter(recvlist);

                recvxml.Seek(recvexdatalen, SeekOrigin.Begin);

                recvxml.Write(data, 0, data.Length);

                recvexdatalen += data.Length;

                DoSplitData(recvxml.ToArray());

                string xml = GetNextXmlData();

                if (xml != null && xml.Length > 0 && this.GetUIAction() != null)
                    this.GetUIAction().AddRevXMLData(xml);


            }
            catch (System.Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }
            finally
            {
                Monitor.Exit(recvlist);
            }

        }
        /*
         * 在数组里面查找指定字符串数据,如果转换了string再查找会造成数据丢失 
         * data 查找数据数组,datalen 数据长度,startpos 开始查找数据位置,strfind 需要被查找字符串
         * 
         */
        private static int FindInArrayByte(byte[] data, int datalen, int startpos, string strfind)
        {
            int pos = 0;
            int retpos = -1;
            bool bSame = false;
            for (pos = startpos; pos < datalen; pos++)
            {
                if (data[pos] == (byte)strfind[0])
                {

                    for (int c = 1; c < strfind.Length; c++)
                    {
                        if ((byte)strfind[c] == data[pos + c])
                            bSame = true;
                        else
                        {
                            bSame = false;
                            break;
                        }

                    }

                    if (bSame)
                    {
                        retpos = pos;
                        break;
                    }
                    else
                    {
                        retpos = -1;
                    }


                }

            }
            return retpos;
        }
        private void LogXmlData(byte[] xml)
        {
            FileStream file = new FileStream("logdata.txt", FileMode.Append);
            file.Write(xml, 0, xml.Length);
            file.Close();
        }
        /*
         * 分拆,结合数据,解密处理
         * data 网络数据
         * 
         * 
         */ 
        private void DoSplitData(byte[] data)
        {

            
            int datastart = 0;
            int dataend = 0;
            int xmlbegin = 0;
            int xmlend = 0;




            string strxmldata = Encoding.Default.GetString(data);

            while (datastart < recvexdatalen)
            {

                int header1 = FindInArrayByte(data, recvexdatalen, datastart, "SS");

                int header2 = FindInArrayByte(data, recvexdatalen, datastart, "FF");

                if (header1 != -1 && header2 != -1)
                {
                    if (header1 > header2)
                    {
                        xmlbegin = header2;
                    }
                    else
                    {
                        xmlbegin = header1;
                    }
                }
                else if (header1 != -1)
                {
                    xmlbegin = header1;
                }
                else if (header2 != -1)
                {
                    xmlbegin = header2;
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("清除数据!");
                    recvexdatalen = 0;

                    Array.Clear(data, 0, data.Length);

                    break;
                }

                int findindex = FindInArrayByte(data, recvexdatalen, datastart, "<end/>");

                if (findindex != -1 && findindex > xmlbegin)
                {
                    xmlend = findindex + 8;
                }
                else
                {
                    System.Diagnostics.Debug.WriteLine("继续接受数据!");
                    break;
                }


                int xmlsize = xmlend - xmlbegin;

                byte[] xmldata = new byte[xmlsize];

                Array.Copy(data, datastart, xmldata, 0, xmlsize);
                string xml = Encoding.Default.GetString(xmldata);
                if (FindInArrayByte(xmldata, xmldata.Length, 0, "FF") != -1 && FindInArrayByte(xmldata, xmldata.Length, 0, "<commblock>") == -1)
                {
                    MemoryStream ms = new MemoryStream(xmldata);

                    byte[] cryptdata = new byte[xmlsize - 2 - 8];

                    dataend += xmlsize;

                    ms.Seek(2, SeekOrigin.Begin);
                    ms.Read(cryptdata, 0, xmlsize - 2 - 8);

                    ms.Close();

                    datastart += xmlsize;

                    MemoryStream cryptstream = new MemoryStream(cryptdata);

                    GZipStream zipstream = new GZipStream(cryptstream, CompressionMode.Decompress);

                    cryptdata = ReadAllBytesFromStream(zipstream);


                    byte[] decryptxml = Decrypt(cryptdata, cryptkey);

                    xml = Encoding.Default.GetString(decryptxml);

                    if (xml.IndexOf("<commblock>") == -1)
                    {
                        System.Diagnostics.Debug.WriteLine("解密错误");
                    }
                    //LogXmlData(decryptxml);
                    //System.Diagnostics.Debug.WriteLine(xml);
                    xml = FilterFlag(xml);
                    recvlist.Add(xml);

                }
                else if (FindInArrayByte(xmldata, xmldata.Length, 0, "SS") != -1 && FindInArrayByte(xmldata, xmldata.Length, 0, "<commblock>") == -1)
                {

                    MemoryStream ms = new MemoryStream(xmldata);

                    byte[] cryptdata = new byte[xmlsize - 2 - 8];

                    dataend += xmlsize;

                    ms.Seek(2, SeekOrigin.Begin);
                    ms.Read(cryptdata, 0, xmlsize - 2 - 8);

                    ms.Close();
                    datastart += xmlsize;

                    byte[] decryptxml = Decrypt(cryptdata, cryptkey);

                    xml = Encoding.Default.GetString(decryptxml);

                    if (xml.IndexOf("<commblock>") == -1)
                    {
                        System.Diagnostics.Debug.WriteLine("解密错误");
                    }

                    //System.Diagnostics.Debug.WriteLine(xml);
                    //LogXmlData(decryptxml);

                    xml = FilterFlag(xml);
                    recvlist.Add(xml);

                }
                else
                {


                    dataend += xmlsize;
                    //LogXmlData(Encoding.Default.GetBytes(xml));
                    //System.Diagnostics.Debug.WriteLine(xml);
                    xml = FilterFlag(xml);
                    recvlist.Add(xml);

                    datastart += xmlsize;
                }

                if (datastart >= data.Length)
                {
                    System.Diagnostics.Debug.WriteLine("超出数据长度!");
                    recvexdatalen = 0;
                }

            }
        }
        private string FilterFlag(string xmldata)
        {
            int pos = xmldata.IndexOf("SS");
            int endpos = xmldata.LastIndexOf("<end/>");
            if (pos != -1 && endpos != -1)
            {
                xmldata.Substring(pos + 2,xmldata.Length - 2 - 8);
                return xmldata;
            }

            return xmldata;
            

        }
        private const int buffer_size = 100;

        /*
         *  从数据流里面读取所有数据
         *  stream 数据流
         * 
         */
        public static byte[] ReadAllBytesFromStream(Stream stream)
        {
            // Use this method is used to read all bytes from a stream.
            int offset = 0;
            int totalCount = 0;
            byte[] buffer = new byte[buffer_size];
            MemoryStream ms = new MemoryStream();
            while (true)
            {

                int bytesRead = stream.Read(buffer, 0, buffer_size);
                if (bytesRead == 0)
                {
                    break;
                }
                ms.Write(buffer, 0, bytesRead);
                offset += bytesRead;
                totalCount += bytesRead;
            }
            return ms.ToArray();
        }
        /*
         * 获取解密后的XML数据
         * 
         */ 

        public string GetNextXmlData()
        {
            string ret = "";
            try
            {
                Monitor.Enter(recvlist);



                if (recvlist.Count > 0)
                {
                    ret = (string)recvlist[0];
                    recvlist.RemoveAt(0);


                }



            }
            catch (System.Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
            }
            finally
            {
                Monitor.Exit(recvlist);
            }

            return ret;


        }

        /*
         * 设置解密的密钥 
         * 
         * 
         */
        public void SetCryptKey(string machinekey, string ticket)
        {
            string shadata = machinekey + ticket;

            SHA1 sha = new SHA1CryptoServiceProvider();

            byte[] result = sha.ComputeHash(Encoding.ASCII.GetBytes(shadata));

            StringBuilder sBuilder = new StringBuilder();

            for (int i = 0; i < result.Length; i++)
            {
                sBuilder.Append(result[i].ToString("x2"));
            }
            cryptkey = sBuilder.ToString();
        }
        public byte[] Decrypt(byte[] bdata, string key)
        {


            Byte[] bkey = Encoding.Default.GetBytes(key);

            int datalen = bdata.Length;// 头尾数据长度
            int keylen = bkey.Length;
            MemoryStream ms = new MemoryStream();
            int d = 0;
            for (int i = 0; i < datalen; i++)
            {
                if (d >= key.Length)
                    d = 0;

                if (bdata[i] != bkey[d])
                {
                    byte c = (byte)(bdata[i] ^ bkey[d]);
                    c++;
                    d++;
                    ms.WriteByte(c);
                }
            }

            return ms.ToArray();


        }
    }
}
